﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Microsoft.Win32;
using System.Diagnostics;
using System.Threading;
using System.Xml.Linq;
using SiteMonitorLogic;
using Growl.Connector;

namespace GrowlSiteMonitor
{
    public partial class MainWindow : Form
    {
        //private volatile Thread _thread = null;
        private GrowlConnector _growl = null;
        private Statistics _stats = new Statistics();
        private DateTime _lastSummarySent = DateTime.MinValue;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void MainWindow_Load(object sender, EventArgs e)
        {
            // set config file
            textBoxConfigLocation.Text = (string)System.Windows.Forms.Application.UserAppDataRegistry.GetValue("ConfigLocation", textBoxConfigLocation.Text);

        }

        private void buttonExit_Click(object sender, EventArgs e)
        {
            // TBD: Ensure all threads are complete

            // close window
            Close();
        }

        private void buttonBrowseConfigLocation_Click(object sender, EventArgs e)
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Filter = "XML files|*.xml|All Files|*.*||";
            dlg.DefaultExt = "xml";
            dlg.FileName = textBoxConfigLocation.Text;
            if (dlg.ShowDialog() == DialogResult.OK)
            {
                textBoxConfigLocation.Text = dlg.FileName;
                System.Windows.Forms.Application.UserAppDataRegistry.SetValue("ConfigLocation", textBoxConfigLocation.Text);
            }
        }

        private void linkLabelEditConfig_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            Process.Start("notepad.exe", textBoxConfigLocation.Text);
        }

        private void buttonCheckAllNow_Click(object sender, EventArgs e)
        {
            timerRunner_Tick(sender, e);
        }

        private void RunTests()
        {
            if (string.IsNullOrEmpty(textBoxConfigLocation.Text))
                return;

            try
            {
                // send begin notification
                Growl.Notify(new Notification("Growl Site Monitor", "BEGIN_CHECKS", "", "Checks beginning.", "Running checks"));

                // clear previous statuses
                listViewStatus.Items.Clear();

                // load config
                XDocument doc = XDocument.Load(textBoxConfigLocation.Text);

                // set timer interval
                TimeSpan interval = TimeSpan.Parse(doc.Root.Attribute("Interval").Value);
                timerRunner.Interval = (int)interval.TotalMilliseconds;

                // run checks
                CheckRunner runner = new CheckRunner();
                runner.CheckComplete += new CheckRunner.CheckCompleteDelegate(runner_CheckComplete);
                runner.Execute(doc.Root);

                // send end notification
                Growl.Notify(new Notification("Growl Site Monitor", "CHECKS_COMPLETE", "", "Checks complete.", "All checks have been executed.  Check previous notifications for errors."));

                // notify with summary?
                if (doc.Root.Attribute("SummaryTime") != null)
                {
                    TimeSpan summaryTime = TimeSpan.Parse(doc.Root.Attribute("SummaryTime").Value);
                    if (_lastSummarySent.DayOfYear != DateTime.Now.DayOfYear &&
                        summaryTime < DateTime.Now.TimeOfDay)
                    {
                        _lastSummarySent = DateTime.Now;

                        decimal overallUptime = 0;
                        string details = "";
                        foreach (string key in _stats.Keys)
                        {
                            decimal uptime = _stats.GetPercentUptime(key);
                            details += string.Format("{0} - {1:f2}% uptime\n", key, uptime);
                            overallUptime += uptime;
                        }

                        overallUptime /= _stats.Keys.Length;

                        Growl.Notify(new Notification("Growl Site Monitor", "SUMMARY", "", string.Format("Summary - {0:f2}% overall uptime", overallUptime), details));

                        _stats = new Statistics();
                    }
                }
            }
            catch (Exception ex)
            {
                CheckResult res = new CheckResult() { Message = "Failed to run checks: " + ex.ToString(), ResultCode = CheckResultCode.Failed };
                runner_CheckComplete(this, new CheckCompleteEventArgs() { Result = res, Check = null });
            }
        }

        public GrowlConnector Growl
        {
            get
            {
                if (_growl == null)
                {
                    // register
                    GrowlConnector growl = new GrowlConnector();

                    Growl.Connector.Application app = new Growl.Connector.Application("Growl Site Monitor");
                    app.Icon = GrowlSiteMonitorResources.GrowlSiteMonitor;

                    // notification types
                    NotificationType beginChecks = new NotificationType("BEGIN_CHECKS", "Begin checks");
                    NotificationType checkSuccess = new NotificationType("CHECK_SUCCESS", "Check passed");
                    NotificationType checkIndeterminate = new NotificationType("CHECK_INDETERMINATE", "Check indeterminate");
                    NotificationType checkFailed = new NotificationType("CHECK_FAILED", "Check failed");
                    NotificationType checksComplete = new NotificationType("CHECKS_COMPLETE", "Checks complete");
                    NotificationType summary = new NotificationType("SUMMARY", "Summary");
                    growl.Register(app, new NotificationType[] {
                        beginChecks, 
                        checkSuccess,
                        checkIndeterminate,
                        checkFailed,
                        checksComplete,
                        summary });

                    _growl = growl;
                }

                return _growl;
            }
        }

        void runner_CheckComplete(object sender, CheckCompleteEventArgs e)
        {
            ListViewItem item = new ListViewItem();
            if (e.Check != null)
            {
                item.Text = e.Check.Name;
                item.SubItems.Add(e.Check.DisplayType);
                item.SubItems.Add(e.Check.Info);
            }
            else
            {
                item.SubItems.Add("");
                item.SubItems.Add("");
            }
            item.SubItems.Add(string.Format("{0}, {1}", e.Result.ResultCode.ToString(), e.Result.Message));
            item.SubItems.Add(DateTime.Now.ToString());
            listViewStatus.Items.Add(item);

            // send growl notification
            string checkName = e.Check == null ? "[unknown]" : e.Check.Name;
            
            if (e.Result.ResultCode == CheckResultCode.Success)
                Growl.Notify(new Notification("Growl Site Monitor", "CHECK_SUCCESS", "", checkName + " passed.", e.Result.Message));
            else if (e.Result.ResultCode == CheckResultCode.Indeterminate)
                Growl.Notify(new Notification("Growl Site Monitor", "CHECK_INDETERMINATE", "", checkName + " indeterminate.", e.Result.Message));
            else if (e.Result.ResultCode == CheckResultCode.Failed)
                Growl.Notify(new Notification("Growl Site Monitor", "CHECK_FAILED", "", checkName + " failed.", e.Result.Message));

            // store stat
            _stats.Record(e.Check.Name, e.Result);
        }

        private void timerRunner_Tick(object sender, EventArgs e)
        {
            // TBD: Move into background thread
            RunTests();

            // notify summary?

            //// ensure that a thread is not currently already running
            //if (_thread != null)
            //    return;

            //// start new thread
            //_thread = new Thread(new ThreadStart(RunTests));
            //_thread.Start();
        }

        private void notifyIcon_Click(object sender, EventArgs e)
        {
            this.Show();
            this.WindowState = FormWindowState.Normal;
            this.Activate();
        }

        private void notifyIcon_BalloonTipShown(object sender, EventArgs e)
        {

        }

        private void MainWindow_Resize(object sender, EventArgs e)
        {
            if (System.Windows.Forms.FormWindowState.Minimized == WindowState)
            {
                this.Hide();
            }
        }

        private void MainWindow_FormClosing(object sender, FormClosingEventArgs e)
        {
            e.Cancel = true;
            this.Hide();
        }

        private void buttonHide_Click(object sender, EventArgs e)
        {
            this.Hide();
        }
    }
}
